Skip to main content

VOIP/Video Consultations

VoipConfig Object

interface VoipConfig {
id?: number;
consultation_id?: number;
api_key?: string;
call_id?: string;
token?: string;
created_at?: string;
updated_at?: string;
}

For VOIP consultation the config data will be in voipConfig and for VIDEO will be in videoConfig, but they share the same data structure so we use one interface for both: VoipConfig.

VOIP and Video consultations are rendered and handled the same way. The difference is to enable the video on Video consultations and disable it for VOIP consultations.

On web, video/VOIP calling is powered by @opentok/client (OpenTok.js) instead of native OpenTok, but the component names and props are unchanged from the React Native SDK.

VOIP/Video Components

These are the components available to handle these consultations:

TBIPublisher
TBISession
TBISubscriber
TBISubscriberView

VOIP/Video Example

Check the below code example of using our ready-to-use components to handle VOIP/Video consultations:

import React, { useState } from 'react';
import {
TBIPublisher,
TBISession,
TBISubscriber,
TBISubscriberView,
} from 'react-web-altibbi';

const Video = ({ data, voip }: { data: any; voip: boolean }) => {
const [audio, setAudio] = useState<boolean>(true);
const [video, setVideo] = useState<boolean>(!voip);
const [camera, setCamera] = useState<'front' | 'back'>('front');

const toggleVideo = () => setVideo((prev) => !prev);
const toggleAudio = () => setAudio((prev) => !prev);
const switchCamera = () =>
setCamera((prev) => (prev === 'front' ? 'back' : 'front'));

const renderSubscribers = (subscriberIds: string[]) => {
if (subscriberIds && subscriberIds.length > 0) {
return subscriberIds.map((streamId) => (
<TBISubscriberView
key={streamId}
streamId={streamId}
style={{ width: '100%', height: '100%' }}
/>
));
}
};

return (
<TBISession
apiKey={data.api_key}
sessionId={data.call_id}
token={data.token}
eventHandlers={{
sessionDisconnected: (event) => {},
streamDestroyed: (event) => {},
error: (event) => {},
}}
>
<TBISubscriber
eventHandlers={{
error: (event) => {},
}}
>
{renderSubscribers}
</TBISubscriber>
<TBIPublisher
style={{
position: 'absolute',
width: 100,
height: 100,
top: 0,
margin: 5,
right: 0,
}}
properties={{
cameraPosition: camera,
publishVideo: video,
publishAudio: audio,
enableDtx: true,
}}
eventHandlers={{
streamDestroyed: (event) => {},
error: (event) => {},
}}
/>
<div
style={{
display: 'flex',
flexDirection: 'row',
padding: 8,
position: 'absolute',
backgroundColor: 'white',
bottom: 0,
left: 0,
right: 0,
justifyContent: 'center',
}}
>
<span
style={{
fontSize: 20,
marginRight: 10,
color: video ? 'blue' : 'red',
cursor: 'pointer',
}}
onClick={toggleVideo}
>
{`Video ${video ? 'On' : 'Off'}`}
</span>
<span
style={{
fontSize: 20,
marginRight: 10,
color: audio ? 'blue' : 'red',
cursor: 'pointer',
}}
onClick={toggleAudio}
>
{`Audio ${audio ? 'On' : 'Off'}`}
</span>
<span
style={{ fontSize: 20, marginRight: 10, cursor: 'pointer' }}
onClick={switchCamera}
>
camera ({camera})
</span>
</div>
</TBISession>
);
};

export default Video;

The browser will prompt the user for camera/microphone permission the first time TBIPublisher initializes — make sure your app is served over HTTPS (or localhost) since getUserMedia requires a secure context.